package com.axapoint.opoc.core.dao;

import java.util.Collection;
import java.util.LinkedList;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.annotations.Cascade;
import org.joda.time.DateTime;
import org.joda.time.Interval;

import com.anasoft.os.daofusion.bitemporal.WrappedBitemporalProperty;
import com.anasoft.os.daofusion.bitemporal.WrappedValueAccessor;

@Entity
@Table(name = "Person")
public class Person extends ObjectRegistration<Person, Person.Value, Person.Bitemporal> {
	private static final long serialVersionUID = 9168710745762860711L;

	@Entity
	@Table(name = "PersonValues")
	public static final class Value extends _Value<Person, Bitemporal> {
		private static final long serialVersionUID = 1L;
		private String cprNo;
		private String firstName;
		private String lastName;
		private String nickFirstName;
		private String nickLastName;

		protected Value() {};
		Value(Person et, String systemId, String userId, Operation operation, String comment, Value value) {
			super(et, systemId, userId, operation, comment);
			this.cprNo = value.cprNo;			
			this.firstName = value.firstName;			
			this.lastName = value.lastName;			
			this.nickFirstName = value.nickFirstName;			
			this.nickLastName = value.nickLastName;			
		}
		public Value(String cprNo, String firstName, String lastName, String nickFirstName, String nickLastName) {
			this.cprNo = cprNo;			
			this.firstName = firstName;			
			this.lastName = lastName;			
			this.nickFirstName = nickFirstName;			
			this.nickLastName = nickLastName;			
		}
		public String getCprNo() {
			return cprNo;
		}
		protected void setCprNo(String cprNo) {
			this.cprNo = cprNo;
		}
		public String getFirstName() {
			return firstName;
		}
		protected void setFirstName(String firstName) {
			this.firstName = firstName;
		}
		public String getLastName() {
			return lastName;
		}
		protected void setLastName(String lastName) {
			this.lastName = lastName;
		}
		public String getNickFirstName() {
			return nickFirstName;
		}
		protected void setNickFirstName(String nickFirstName) {
			this.nickFirstName = nickFirstName;
		}
		public String getNickLastName() {
			return nickLastName;
		}
		protected void setNickLastName(String nickLastName) {
			this.nickLastName = nickLastName;
		}
		@Override
		public String diff(_Value<Person, Bitemporal> otherValue, DateTime t0, DateTime t1) {
			StringBuffer sb = new StringBuffer();
			Value other = (Value)otherValue;
			
			if (cprNo != null && !cprNo.equals(other.cprNo)) {
				sb.append("Person.cprNo: ").append(cprNo).append(" - ").append(other.cprNo).append('\n');
			}
			if (firstName != null && !firstName.equals(other.firstName)) {
				sb.append("Person.firstName: ").append(firstName).append(" - ").append(other.firstName).append('\n');
			}
			if (lastName != null && !lastName.equals(other.lastName)) {
				sb.append("Person.lastName: ").append(lastName).append(" - ").append(other.lastName).append('\n');
			}
			if (nickFirstName != null && !nickFirstName.equals(other.nickFirstName)) {
				sb.append("Person.nickFirstName: ").append(nickFirstName).append(" - ").append(other.nickFirstName).append('\n');
			}
			if (nickLastName != null && !nickLastName.equals(other.nickLastName)) {
				sb.append("Person.nickLastName: ").append(nickLastName).append(" - ").append(other.nickLastName).append('\n');
			}
			
			return sb.toString();
		}
		@Override
		public String toString() {
			StringBuffer sb = new StringBuffer();
			sb.append(super.toString());
			sb.append("  cprNo=").append(cprNo).append('\n');
			sb.append("  firstName=").append(firstName).append('\n');
			sb.append("  lastName=").append(lastName).append('\n');
			sb.append("  nickFirstName=").append(nickFirstName).append('\n');
			sb.append("  nickLastName=").append(nickLastName).append('\n');

			int cnt = 0;
			for (Engagement.Value v : getEntity().getEngagements()) {
				if (v.getBitemporal().getValidityInterval().contains(getBitemporal().getValidityInterval().getStart())) {
					cnt++;
				}
			}
			sb.append("  #engagements=").append(cnt).append('\n');			
			
			return sb.toString();
		}
	}
	
	@Entity
	@Table(name = "PersonBitemporal")
	public static final class Bitemporal extends _Bitemporal<Bitemporal, Value> {
		private static final long serialVersionUID = -2132187534862370208L;
		
		protected Bitemporal() {}
	    private Bitemporal(Person.Value value, Interval validityInterval) {
	        super(value, validityInterval);
	    }
	    
	    @Override
	    public Bitemporal copyWith(Interval validityInterval) {
	    	return new Bitemporal(value, validityInterval);
	    }
	}

	@SuppressWarnings("deprecation")
	@OneToMany(fetch = FetchType.LAZY)
    @Cascade(value = { org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE_ORPHAN })
    @JoinColumn(name="personId")
    private Collection<Engagement.Value> engagements = new LinkedList<Engagement.Value>();	

	public Person() {
		super();
	}
	public Collection<Engagement.Value> getEngagements() {
		return engagements;
	}
	protected void setEngagements(Collection<Engagement.Value> engagements) {
		this.engagements = engagements;
	}
    public WrappedBitemporalProperty<Value, Bitemporal> getValues() {
    	return new WrappedBitemporalProperty<Value, Bitemporal>(values, new WrappedValueAccessor<Value,Bitemporal>() {
			private static final long serialVersionUID = 1L;

			@Override
			public Bitemporal wrapValue(Value value, Interval validityInterval) {
				Bitemporal bi = new Bitemporal(value, validityInterval);
				return bi;
			}
    	});
    }
}
